﻿#include "chartwave.h"
#include "ui_chartwave.h"
#include <QFontDialog>


#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif


const QVector<QColor> g_graphColor = {
    QColor( 65, 105, 255),
    QColor(  0, 250,   0),
    QColor(119, 136, 153),
    QColor(135, 206, 250),
    QColor(  0, 139, 139),
    QColor(127, 255, 170),
    QColor( 60, 179, 113),
    QColor(152, 251, 152),
    QColor( 34, 139,  34),
    QColor(127, 255,   0),
    QColor(255, 255,   0),
    QColor(222, 184, 135),
    QColor(255, 127,  80)
};


ChartWave::ChartWave(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ChartWave)
    , m_showFreqWave(true)
    , m_showFlowText(false)
    , m_currentCh(-1)
    , m_xTimeRange(0, 100)
    , m_yTimeRange(-1, 1)
    , m_xFreqRange(0, 100)
    , m_yFreqRange(-1, 1)
    , m_titleVisible1(false)
    , m_titleVisible2(false)
    , m_filterType(BANDPASS)
    , m_winType(HANN)
    , m_scale(64)
    , m_freqUpper(2000)
    , m_freqLower(10)
{
    ui->setupUi(this);

    setLayout(ui->vLay_chart);

    setContextMenuPolicy(Qt::CustomContextMenu);
    ui->timeWave->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->freqWave->setContextMenuPolicy(Qt::CustomContextMenu);

    setAcceptDrops(true);

    // meun
    m_rightClickMenu = new QMenu(this);
    m_menuFilter = new QMenu(tr("滤波"), this);
//    m_filter = new QAction(tr("滤波"), this);
    m_freqWave = new QAction(tr("隐藏频域波形"), this);
    m_flowText = new QAction(tr("显示跟随文本"), this);
    m_menuDelGraph = new QMenu(tr("删除曲线"), this);
    m_cleanGraph = new QAction(tr("清空曲线"), this);
    m_selectZoom = new QAction(tr("框选缩放"), this);
    m_selectDrag = new QAction(tr("鼠标拖拽"), this);
    m_restore = new QAction(tr("还原"), this);
    m_menuColor = new QMenu(tr("曲线颜色"), this);
    m_setting = new QAction(tr("设置"), this);
    m_rightClickMenu->addMenu(m_menuFilter);
    m_rightClickMenu->addAction(m_freqWave);
    m_rightClickMenu->addAction(m_flowText);
    m_rightClickMenu->addSeparator();
    m_rightClickMenu->addMenu(m_menuColor);
    m_rightClickMenu->addMenu(m_menuDelGraph);
    m_rightClickMenu->addAction(m_cleanGraph);
    m_rightClickMenu->addSeparator();
    m_rightClickMenu->addAction(m_selectZoom);
    m_rightClickMenu->addAction(m_selectDrag);
    m_rightClickMenu->addSeparator();
    m_rightClickMenu->addAction(m_restore);
    m_rightClickMenu->addSeparator();
    m_rightClickMenu->addAction(m_setting);
    m_selectZoom->setCheckable(true);
    m_selectDrag->setCheckable(true);
    m_selectZoom->setChecked(true);

//    connect(m_filter,       &QAction::triggered, this, &ChartWave::action_filter_triggered);
    connect(m_flowText,     &QAction::triggered, this, &ChartWave::action_flowText_triggered);
    connect(m_freqWave,     &QAction::triggered, this, &ChartWave::action_freqWave_triggered);
    connect(m_cleanGraph,   &QAction::triggered, this, &ChartWave::cleanGraph_triggered);
    connect(m_selectZoom,   &QAction::triggered, this, &ChartWave::selectArea_triggered);
    connect(m_selectDrag,   &QAction::triggered, this, &ChartWave::selectArea_triggered);
    connect(m_restore,      &QAction::triggered, this, &ChartWave::actionRestore);
    // 触发右击菜单事件
    connect(this,           &ChartWave::customContextMenuRequested,     this, &ChartWave::rightMeun_clicked);
    connect(ui->timeWave,   &QCustomPlot::customContextMenuRequested,   this, &ChartWave::rightMeun_clicked);
    connect(ui->freqWave,   &QCustomPlot::customContextMenuRequested,   this, &ChartWave::rightMeun_clicked);
    // 鼠标事件
    connect(ui->timeWave,   &QCustomPlot::mousePress,   this, &ChartWave::mousePressEvent);
    connect(ui->freqWave,   &QCustomPlot::mousePress,   this, &ChartWave::mousePressEvent);
    connect(ui->timeWave,   &QCustomPlot::mouseMove,    this, &ChartWave::mouseMoveEvent);
    connect(ui->freqWave,   &QCustomPlot::mouseMove,    this, &ChartWave::mouseMoveEvent);
    connect(ui->timeWave,   &QCustomPlot::mouseRelease, this, &ChartWave::mouseReleaseEvent);
    connect(ui->freqWave,   &QCustomPlot::mouseRelease, this, &ChartWave::mouseReleaseEvent);
    // 坐标范围改变事件
    connect(ui->timeWave->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(timeWave_xRangeChanged(QCPRange)));
    connect(ui->timeWave->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(timeWave_yRangeChanged(QCPRange)));
    // 频谱
//    connect(this, SIGNAL(freqXRangeChanged(double, double, bool)), this, SLOT(setFreqXRange(double, double, bool)), Qt::QueuedConnection);
//    connect(this, SIGNAL(freqYRangeChanged(double, double, bool)), this, SLOT(setFreqYRange(double, double, bool)), Qt::QueuedConnection);
    connect(this, &ChartWave::freqData,                            this, &ChartWave::setFreqGraphData,              Qt::QueuedConnection);

    /**
      时域波形
     */
    m_title1 = new QCPTextElement(ui->timeWave);
    ui->timeWave->plotLayout()->insertRow(0);
    ui->timeWave->plotLayout()->addElement(0, 0, m_title1);
    m_vTimeTrackLine = new QCPItemStraightLine(ui->timeWave);
    m_vTimeTrackLine->setPen(QPen(Qt::black, 2, Qt::DashLine));
    m_vTimeTrackLine->point1->setCoords(0, 0);
    m_vTimeTrackLine->point2->setCoords(0, 0);
    m_vTimeTrackLine->setVisible(true);
    m_hTimeTrackLine = new QCPItemStraightLine(ui->timeWave);
    m_hTimeTrackLine->setPen(QPen(Qt::black, 2, Qt::DashLine));
    m_hTimeTrackLine->point1->setCoords(0, 0);
    m_hTimeTrackLine->point2->setCoords(0, 0);
    m_hTimeTrackLine->setVisible(true);
    m_timeText = new QCPItemText(ui->timeWave);
    m_timeText->setPen(QPen(Qt::black));
    m_timeText->setFont(QFont(font().family(), 10));
    m_timeText->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_timeText->position->setType(QCPItemPosition::ptAxisRectRatio);
    m_timeText->position->setCoords(0.82, 0.87);
    m_timeText->setText("x= , y= ");
    m_timeText->setPadding(QMargins(5, 2, 2, 2));
    m_timeText->setVisible(false);
//    ui->timeWave->legend->setVisible(true);
    ui->timeWave->legend->setSelectableParts(QCPLegend::spItems);
    ui->timeWave->setInteractions(QCP::iSelectLegend | QCP::iSelectAxes | QCP::iRangeZoom);
    // 设置框选放大
    ui->timeWave->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    // 设置框选边框颜色，宽度，线样式
    ui->timeWave->selectionRect()->setPen(QPen(QPen(Qt::black, 2, Qt::DashLine)));
    // 设置框选颜色，透明度
    ui->timeWave->selectionRect()->setBrush(QBrush(QColor(0, 0, 100, 50)));

    /**
      频域波形
     */
    m_title2 = new QCPTextElement(ui->freqWave);
    ui->freqWave->plotLayout()->insertRow(0);
    ui->freqWave->plotLayout()->addElement(0, 0, m_title2);
    m_vFreqTrackLine = new QCPItemStraightLine(ui->freqWave);
    m_vFreqTrackLine->setPen(QPen(Qt::black, 2, Qt::DashLine));
    m_vFreqTrackLine->setVisible(true);
    m_vFreqTrackLine->point1->setCoords(0, 0);
    m_vFreqTrackLine->point2->setCoords(0, 0);
    m_hFreqTrackLine = new QCPItemStraightLine(ui->freqWave);
    m_hFreqTrackLine->setPen(QPen(Qt::black, 2, Qt::DashLine));
    m_hFreqTrackLine->setVisible(true);
    m_hFreqTrackLine->point1->setCoords(0, 0);
    m_hFreqTrackLine->point2->setCoords(0, 0);
    m_freqText = new QCPItemText(ui->freqWave);
    m_freqText->setPen(QPen(Qt::black));
    m_freqText->setFont(QFont(font().family(), 10));
    m_freqText->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_freqText->position->setType(QCPItemPosition::ptAxisRectRatio);
    m_freqText->position->setCoords(0.82, 0.87);
    m_freqText->setText("x= , y= ");
    m_freqText->setPadding(QMargins(5, 2, 2, 2));
    m_freqText->setVisible(false);
    ui->freqWave->setInteractions(QCP::iSelectLegend | QCP::iSelectAxes | QCP::iRangeZoom);
    ui->freqWave->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    ui->freqWave->selectionRect()->setPen(QPen(QPen(Qt::black, 2, Qt::DashLine)));
    ui->freqWave->selectionRect()->setBrush(QBrush(QColor(0, 0, 100, 50)));
}

ChartWave::~ChartWave()
{
}

void ChartWave::showFrequencyWave(bool visible)
{
    if(visible)
    {
        m_showFreqWave = true;
        m_freqWave->setText("隐藏频谱波形");
        ui->freqWave->show();
    }
    else
    {
        m_showFreqWave = false;
        m_freqWave->setText("显示频谱波形");
        ui->freqWave->hide();
    }
}

void ChartWave::restoreTimeWave()
{
    ui->timeWave->xAxis->setRange(m_xTimeRange);
    ui->timeWave->yAxis->setRange(m_yTimeRange);
    ui->timeWave->replot();
}

void ChartWave::restoreFreqWave()
{
    ui->freqWave->xAxis->setRange(m_xFreqRange);
    ui->freqWave->yAxis->setRange(m_yFreqRange);
    ui->freqWave->replot();
}

void ChartWave::setFilterParams(FilterType type, FilterWindowType wType, int scale, qreal fUpper, qreal fLower)
{
    m_filterType = type;
    m_winType = wType;
    m_scale = scale;
    m_freqUpper = fUpper;
    m_freqLower = fLower;
}

void ChartWave::calcFFTWave(int ch, QVector<double> wave)
{
#if 0
    if(wave.size() <= 0)
        return;
    int len = wave.size();
    int flen = 1;
    while (true) {
        if(flen > len)
            break;
        else
            flen *= 2;
    }
    flen /= 2;
    QVector<std::complex<double>> in(flen), out(flen);
    for(int i = 0; i < flen; i++)
    {
        in[i] = std::complex<double>(wave.at(i), 0);
    }
    FourierTransform(in, out);

    int length = flen / 2 + 1;
    QVector<double> keys(length), values(length);
    len = out.size();
    double xUpper = 0, yLower = 0, yUpper = 0;
    qreal freq = m_chFreq[ch];
    for(int i = 0; i < length; i++)
    {
        if(qFuzzyIsNull(freq))
            keys[i] = i;
        else
            keys[i] = freq / flen * i;
        double v = out[i].real() / (flen / 2 + 1) * 2.;
        values[i] = v;

        if(0 == i)
            yLower = yUpper = v;
        if(yLower > v)
            yLower = v;
        if(yUpper < v)
            yUpper = v;
    }
    xUpper = keys.back();
#endif
    QVector<double> keys, values;
    frequencySpectrum(wave, values);
    double xUpper = 0, yLower = 0, yUpper = 0;
    double freq = m_chFreq[ch];
    int flen = values.length() / 2 + 1;
    yLower = yUpper = values.front();
    for(int i = 0; i < values.size(); i++)
    {
        keys.append(freq / flen * i);
        if(yLower > values.at(i))
            yLower = values.at(i);
        if(yUpper < values.at(i))
            yUpper = values.at(i);
    }
    xUpper = keys.back();
    emit setFreqXRange(0, xUpper, true);
    emit setFreqYRange(yLower, yUpper, true);
    emit freqData(ch, keys, values);
}

void ChartWave::setEnable_Filter(bool enable)
{
    m_menuFilter->setEnabled(enable);
}

void ChartWave::setEnable_FFTCurve(bool enable)
{
    m_freqWave->setEnabled(enable);
}

void ChartWave::setEnable_Text(bool enable)
{
    m_flowText->setEnabled(enable);
}

void ChartWave::setEnable_DeleteCurve(bool enable)
{
    m_menuDelGraph->setEnabled(enable);
}

void ChartWave::setEnable_CleanCurve(bool enable)
{
    m_cleanGraph->setEnabled(enable);
}

void ChartWave::setEnable_SelectZoom(bool enable)
{
    m_selectZoom->setEnabled(enable);
}

void ChartWave::setEnable_MouseZoom(bool enable)
{
    m_selectDrag->setEnabled(enable);
}

void ChartWave::setEnable_GraphColor(bool enable)
{
    m_menuColor->setEnabled(enable);
}

void ChartWave::setEnable_Recover(bool enable)
{
    m_restore->setEnabled(enable);
}

void ChartWave::setVisible_TimeTitle(bool visible)
{
    if(m_titleVisible1 != visible)
    {
        m_titleVisible1 = visible;
        m_title1->setVisible(visible);
        ui->timeWave->replot();
    }
}

void ChartWave::setVisible_FreqTitle(bool visible)
{
    if(m_titleVisible2 != visible)
    {
        m_titleVisible2 = visible;
        m_title2->setVisible(visible);
        ui->freqWave->replot();
    }
}

void ChartWave::setVisible_Filter(bool visible)
{
    m_menuFilter->setVisible(visible);
}

void ChartWave::setVisible_FFTCurve(bool visible)
{
    m_freqWave->setVisible(visible);
}

void ChartWave::setVisible_Text(bool visible)
{
    m_flowText->setVisible(visible);
}

void ChartWave::setVisible_DeleteCurve(bool visible)
{
    m_menuDelGraph->setVisible(visible);
}

void ChartWave::setVisible_CleanCurve(bool visible)
{
    m_cleanGraph->setVisible(visible);
}

void ChartWave::setVisible_SelectZoom(bool visible)
{
    m_selectZoom->setVisible(visible);
}

void ChartWave::setVisible_MouseZoom(bool visible)
{
    m_selectDrag->setVisible(visible);
}

void ChartWave::setVisible_GraphColor(bool visible)
{
    m_menuColor->setVisible(visible);
}

void ChartWave::setVisible_Recover(bool visible)
{
    m_restore->setVisible(visible);
}



void ChartWave::action_filter_triggered()
{
    // 历史数据滤波
    int graphCount = ui->timeWave->graphCount();
    if(graphCount <= 0)
        return;
    QVector<qreal> key, value;
    const QSharedPointer<QCPGraphDataContainer> data = ui->timeWave->graph(0)->data();
    const QCPGraphDataContainer *d = data.data();
    for(auto it = d->constBegin(); it != d->constEnd(); ++it)
    {
        key.append(it->key);
        value.append(it->value);
    }

//    if(m_ja_chInfo.size() <= 0)
//    {
//        QMessageBox::warning(this, "警告", "信息不全，无法计算滤波");
//        return;
//    }
//    QJsonObject obj = m_ja_chInfo.at(0).toObject();

//    int ch = obj["channelNumber"].toInt();

//    int freq = obj["freq"].toInt();
    Filter f(m_filterType, m_winType, m_scale, 40000, m_freqLower, m_freqUpper);
    f.Convolution(value);
    for(int i = 0; i < f.OutData.size(); i++)
    {
        if(m_yTimeRange.lower > f.OutData.at(i))
            m_yTimeRange.lower = f.OutData.at(i);
        if(m_yTimeRange.upper < f.OutData.at(i))
            m_yTimeRange.upper = f.OutData.at(i);
    }

    setTimeYRange(m_yTimeRange);
//    setTimeGraphData(ch, key, f.OutData);
}

void ChartWave::action_freqWave_triggered()
{
    if(m_showFreqWave)
    {
        showFrequencyWave(false);
    }
    else
    {
        showFrequencyWave(true);
    }
}

void ChartWave::action_flowText_triggered()
{
    if(m_showFlowText)
    {
        m_timeText->setVisible(false);
        m_freqText->setVisible(false);
        ui->timeWave->replot();
        ui->freqWave->replot();

        m_showFlowText = false;
        m_flowText->setText(tr("显示跟随文本"));
    }
    else
    {
        m_timeText->setVisible(true);
        m_freqText->setVisible(true);
        ui->timeWave->replot();
        ui->freqWave->replot();

        m_showFlowText = true;
        m_flowText->setText(tr("隐藏跟随文本"));
    }
}

void ChartWave::graphColor_triggered()
{
    // change graph color
    QAction *action = qobject_cast<QAction*>(sender());
    QString str = action->text();
    int ch = str.right(str.length() - str.lastIndexOf('-') - 1).toInt();
    int index = m_chInfo[ch].chIndex;

    QColor color = QColorDialog::getColor(Qt::white, this);
    m_chInfo[ch].color = color;
    ui->timeWave->graph(index)->setPen(QPen(color, 1));
    ui->timeWave->replot();
}

void ChartWave::delGraph_triggered()
{
    QAction *action = qobject_cast<QAction*>(sender());
    QString str = action->text();
    int ch = str.right(str.length() - str.lastIndexOf('-') - 1).toInt();
    deleteGraph(ch);

    ui->timeWave->replot();
    ui->freqWave->replot();
}

void ChartWave::cleanGraph_triggered()
{
    while (!m_chIndex.isEmpty())
        deleteGraphByIndex(m_chIndex.firstKey());

    ui->timeWave->replot();
    ui->freqWave->replot();
}

void ChartWave::selectArea_triggered()
{
    QAction *action = qobject_cast<QAction*>(sender());
    if(action == m_selectZoom)
    {
        m_selectZoom->setChecked(true);
        m_selectDrag->setChecked(false);

        ui->timeWave->setInteraction(QCP::iRangeDrag, false);
        ui->timeWave->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);

        ui->freqWave->setInteraction(QCP::iRangeDrag, false);
        ui->freqWave->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    }
    else if(action == m_selectDrag)
    {
        m_selectZoom->setChecked(false);
        m_selectDrag->setChecked(true);

        ui->timeWave->setInteraction(QCP::iRangeDrag, true);
        ui->timeWave->setSelectionRectMode(QCP::SelectionRectMode::srmNone);

        ui->freqWave->setInteraction(QCP::iRangeDrag, true);
        ui->freqWave->setSelectionRectMode(QCP::SelectionRectMode::srmNone);
    }
}

void ChartWave::timeWave_xRangeChanged(const QCPRange &newRange)
{
    emit timeXRangeChanged(newRange);
}

void ChartWave::timeWave_yRangeChanged(const QCPRange &newRange)
{
    emit timeYRangeChanged(newRange);
}

void ChartWave::actionRestore()
{
    restoreTimeWave();
    restoreFreqWave();
}

void ChartWave::rightMeun_clicked(const QPoint &pos)
{
    Q_UNUSED(pos)
    for(auto d : m_menuDelGraph->actions())
    {
        m_menuDelGraph->removeAction(d);
        delete d;
        d = nullptr;
    }
    for(auto d : m_menuColor->actions())
    {
        m_menuColor->removeAction(d);
        delete d;
        d = nullptr;
    }
    for(auto d : m_menuFilter->actions())
    {
        m_menuFilter->removeAction(d);
        delete d;
        d = nullptr;
    }
    for(auto d : m_chInfo)
    {
        QString name = QString("%1-%2").arg(d.chName).arg(d.chNum);
        QAction *graphColor = new QAction(name, this);
        connect(graphColor, &QAction::triggered, this, &ChartWave::graphColor_triggered);
        m_menuColor->addAction(graphColor);

        QAction *graph = new QAction(name, this);
        connect(graph, &QAction::triggered, this, &ChartWave::delGraph_triggered);
        m_menuDelGraph->addAction(graph);

        QAction *filter = new QAction(name, this);
        connect(filter, &QAction::triggered, this, &ChartWave::action_filter_triggered);
        m_menuFilter->addAction(filter);
    }
    m_rightClickMenu->exec(QCursor::pos());
}

void ChartWave::setFrequencyWaveVisible(bool visible)
{
    showFrequencyWave(visible);
}

qint8 ChartWave::currentChGraph() const
{
    return m_currentCh;
}

void ChartWave::setChCount(int count)
{
    // 需要对时域和频域窗口同时操作，并且需要同时操作对跟随游标
    // 判断现有曲线数量，少了增加，多了删除

    // 增加
    int gCount = ui->timeWave->graphCount();
    if(gCount < count)
    {
        while(gCount < count)
        {
//            addGraph(QJsonObject());

            gCount = ui->timeWave->graphCount();
        }
    }
    // 删除
    else
    {
        gCount = ui->timeWave->graphCount();
        while(ui->timeWave->graphCount() > count)
        {
            gCount = ui->timeWave->graphCount() - 1;

            deleteGraph(gCount);
        }
    }
}



bool ChartWave::chNumberExist(int ch)
{
    return m_chIndex.contains(ch);
}

void ChartWave::setTimeTitle(const QString &title)
{
    m_title1->setText(title);
    setVisible_TimeTitle(true);
}

void ChartWave::setFreqTitle(const QString &title)
{
    m_title2->setText(title);
    setVisible_FreqTitle(true);
}

void ChartWave::setTimeTitleFont(const QFont &font)
{
    m_title1->setFont(font);
    ui->timeWave->replot();
}

void ChartWave::setFreqTitleFont(const QFont &font)
{
    m_title2->setFont(font);
    ui->freqWave->replot();
}

void ChartWave::setTimeXRange(const QCPRange &newRange, bool fixRange)
{
    if(fixRange)
    {
        m_xTimeRange = newRange;
    }
    ui->timeWave->xAxis->setRange(newRange);
    ui->timeWave->replot();
}

void ChartWave::setTimeXRange(double lower, double upper, bool fixRange)
{
    if(fixRange)
    {
        m_xTimeRange.lower = lower;
        m_xTimeRange.upper = upper;
    }
    ui->timeWave->xAxis->setRange(lower, upper);
    ui->timeWave->replot();
}

void ChartWave::setTimeYRange(const QCPRange &newRange, bool fixRange)
{
    if(fixRange)
    {
        m_yTimeRange = newRange;
    }
    ui->timeWave->yAxis->setRange(newRange);
    ui->timeWave->replot();
}

void ChartWave::setTimeYRange(double lower, double upper, bool fixRange)
{
    if(fixRange)
    {
        m_yTimeRange.lower = lower;
        m_yTimeRange.upper = upper;
    }
    ui->timeWave->yAxis->setRange(lower, upper);
    ui->timeWave->replot();
}

void ChartWave::setFreqXRange(const QCPRange &newRange, bool fixRange)
{
    if(fixRange)
    {
        m_xFreqRange = newRange;
    }
    ui->freqWave->xAxis->setRange(newRange);
    ui->freqWave->replot();
}

void ChartWave::setFreqXRange(double lower, double upper, bool fixRange)
{
    if(fixRange)
    {
        m_xFreqRange.lower = lower;
        m_xFreqRange.upper = upper;
    }
    ui->freqWave->xAxis->setRange(lower, upper);
    ui->freqWave->replot();
}

void ChartWave::setFreqYRange(const QCPRange &newRange, bool fixRange)
{
    if(fixRange)
    {
        m_yFreqRange = newRange;
    }
    ui->freqWave->yAxis->setRange(newRange);
    ui->freqWave->replot();
}

void ChartWave::setFreqYRange(double lower, double upper, bool fixRange)
{
    if(fixRange)
    {
        m_yFreqRange.lower = lower;
        m_yFreqRange.upper = upper;
    }
    ui->freqWave->yAxis->setRange(lower, upper);
    ui->freqWave->replot();
}

void ChartWave::setTimeGraphData(int chNumber, const QVector<double> &keys, const QVector<double> &values)
{
    if(!m_chInfo.contains(chNumber))
    {
        qInfo() << "ch is not exist";
        qt_assert_x("setTimeGraphData(int, const QVector<double>&, const QVector<double>&)", "ch is not exist", __FILE__, __LINE__);
        return;
    }
    int index = m_chInfo[chNumber].chIndex;

    ui->timeWave->graph(index)->setData(keys, values);
    ui->timeWave->replot();
}

void ChartWave::setFreqGraphData(int chNumber, const QVector<double> &keys, const QVector<double> &values)
{
    if(!m_chInfo.contains(chNumber))
    {
        qInfo() << "ch is not exist";
        qt_assert_x("setFreqGraphData(int, const QVector<double>&, const QVector<double>&)", "ch is not exist", __FILE__, __LINE__);
        return;
    }

    int index = m_chInfo[chNumber].chIndex;
    ui->freqWave->graph(index)->setData(keys, values);
    ui->freqWave->replot();

}

void ChartWave::addGraph(const ChInfo &graphInfo)
{
    // 查重
    bool exist = false;
    for(auto it = m_chIndex.constBegin(); it != m_chIndex.constEnd(); it++)
    {
        if(it.value() == graphInfo.chNum)
        {
            exist = true;
            break;
        }
    }
    if(exist)
    {
        qInfo() << "该通道已存在，添加失败。";
        return;
    }

    int gCount = ui->timeWave->graphCount();
    ChInfo temp = graphInfo;
    temp.chIndex = gCount;

    QColor color;
    if(gCount < g_graphColor.size() || gCount >= 0)
        color = g_graphColor[gCount];
    else
        color = g_graphColor[temp.chIndex];
    temp.color = color;
    QString name = graphInfo.chName;
    if(name.isEmpty())
        name = QString("曲线%1-%2").arg(graphInfo.chIndex).arg(graphInfo.chNum);

    ui->timeWave->addGraph();
    ui->timeWave->graph(gCount)->setPen(QPen(color, 1));
    ui->timeWave->graph(gCount)->setName(name);
    m_chIndex.insert(temp.chIndex, temp.chNum);
    m_chInfo.insert(temp.chNum, temp);

    // 时域曲线跟随游标
    QCPItemTracer* tracer = new QCPItemTracer(ui->timeWave);
    tracer->setPen(QPen(Qt::darkYellow));
    tracer->setStyle(QCPItemTracer::tsPlus);
    tracer->setVisible(true);
    m_timeTracerList << tracer;

    // 频域曲线
    ui->freqWave->addGraph();
    ui->freqWave->graph(gCount)->setPen(QPen(color, 1));
    // 频域曲线跟随游标
    tracer = new QCPItemTracer(ui->freqWave);
    tracer->setPen(QPen(Qt::darkYellow));
    tracer->setStyle(QCPItemTracer::tsPlus);
    tracer->setVisible(true);
    m_freqTracerList << tracer;
}

void ChartWave::deleteGraphByIndex(int index)
{
    if(!m_chIndex.contains(index))
    {
        qInfo() << "deleteGraphByIndex(int index): index out of range";
        return;
    }
    /**
      1. 找到 m_chIndex 和 m_chInfo 对应的信息并删除
      2. 找到 m_chIndex 和 m_chInfo 中 index > index，需要 --index
     */
    int ch = m_chIndex[index];
    m_chIndex.clear();
    m_chInfo.remove(ch);

    for(auto it = m_chInfo.begin(); it != m_chInfo.end(); it++)
    {
        ChInfo temp = it.value();
        if(temp.chIndex > index)
            --temp.chIndex;
        m_chInfo.insert(it.key(), temp);
        m_chIndex.insert(temp.chIndex, temp.chNum);
    }

    ui->timeWave->removeGraph(index);
    ui->timeWave->removeItem(m_timeTracerList.at(index));
    m_timeTracerList.removeAt(index);

    ui->freqWave->removeGraph(index);
    ui->freqWave->removeItem(m_freqTracerList.at(index));
    m_freqTracerList.removeAt(index);
}

void ChartWave::deleteGraph(int ch)
{
    if(!m_chInfo.contains(ch))
    {
        qInfo() << "deleteGraph(int ch): ch is not exist";
        return;
    }
    /**
      1. 找到 m_chIndex 和 m_chInfo 对应的信息并删除
      2. 找到 m_chIndex 和 m_chInfo 中 index > index，需要 --index
     */
    int index = m_chInfo[ch].chIndex;
    m_chIndex.clear();
    m_chInfo.remove(ch);

    for(auto it = m_chInfo.begin(); it != m_chInfo.end(); it++)
    {
        ChInfo temp = it.value();
        if(temp.chIndex > index)
            --temp.chIndex;
        m_chInfo.insert(it.key(), temp);
        m_chIndex.insert(temp.chIndex, temp.chNum);
    }

    ui->timeWave->removeGraph(index);
    ui->timeWave->removeItem(m_timeTracerList.at(index));
    m_timeTracerList.removeAt(index);

    ui->freqWave->removeGraph(index);
    ui->freqWave->removeItem(m_freqTracerList.at(index));
    m_freqTracerList.removeAt(index);
}

void ChartWave::updateChNameByIndex(int index, const QString &name)
{
    if(!m_chIndex.contains(index))
    {
        qInfo() << "updateChNameByIndex(int index, const QString &name): index out of range";
        return;
    }

    int ch = m_chIndex[index];
    ChInfo info = m_chInfo[ch];
    if(info.chName == name)
        return;
    info.chName = name;
    QString str = QString("%1-%1").arg(name).arg(ch);
    ui->timeWave->graph(index)->setName(str);
    ui->timeWave->replot();
    m_chInfo.insert(ch, info);
}

void ChartWave::updateChName(int ch, const QString &name)
{
    if(!m_chInfo.contains(ch))
    {
        qInfo() << "updateChName(int ch, const QString &name): ch is not exist";
        return;
    }

    ChInfo info = m_chInfo[ch];
    if(info.chName == name)
        return;
    info.chName = name;
    QString str = QString("%1-%1").arg(name).arg(ch);
    ui->timeWave->graph(info.chIndex)->setName(str);
    ui->timeWave->replot();
    m_chInfo.insert(ch, info);
}

void ChartWave::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls() || event->mimeData()->hasText())
        event->acceptProposedAction();
    else
        event->ignore();
}

void ChartWave::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasUrls())
    {
        QList<QUrl> list = event->mimeData()->urls();
        for(auto d : list)
        {
            qInfo() << d.toLocalFile();
        }
    }
    else if(event->mimeData()->hasText())
    {
//        QJsonObject obj = QJsonDocument::fromJson(event->mimeData()->text().toUtf8()).object();
//        bool exist = false;
//        for(auto d : m_ja_chInfo)
//        {
//            if(d.toObject() == obj)
//            {
//                exist = true;
//                break;
//            }
//        }
//        if(!exist)
//        {
//            int count = ui->timeWave->graphCount();
//            addGraph(obj);

//            emit graphAction(GO_ADD, count, obj);
//        }
    }
    else
    {
        event->ignore();
    }
}


void ChartWave::mousePressEvent(QMouseEvent *e)
{
    bool timewave = true;
    if(ui->timeWave->geometry().contains(this->mapFromGlobal(QCursor::pos())))
        timewave = true;
    else if(ui->freqWave->geometry().contains(this->mapFromGlobal(QCursor::pos())))
        timewave = false;
    else
        return;
    switch (e->button()) {
        case Qt::LeftButton:
        {
            if(timewave)
            {
                if (ui->timeWave->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
                    ui->timeWave->axisRect()->setRangeDrag(ui->timeWave->xAxis->orientation());
                else if (ui->timeWave->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
                    ui->timeWave->axisRect()->setRangeDrag(ui->timeWave->yAxis->orientation());
                else
                    ui->timeWave->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
            }
            else
            {
                if (ui->freqWave->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
                    ui->freqWave->axisRect()->setRangeDrag(ui->freqWave->xAxis->orientation());
                else if (ui->freqWave->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
                    ui->freqWave->axisRect()->setRangeDrag(ui->freqWave->yAxis->orientation());
                else
                    ui->freqWave->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
            }
            break;
        }
        case Qt::MidButton:
        {
            if(timewave)
            {
                restoreTimeWave();
            }
            else
            {
                restoreFreqWave();
            }
        }
            break;
        case Qt::RightButton:
            break;
        default:
            break;
        }
        QWidget::mousePressEvent(e);
}

void ChartWave::mouseMoveEvent(QMouseEvent *e)
{
    double x = e->pos().x();
    double tly = ui->timeWave->yAxis->range().lower, thy = ui->timeWave->yAxis->range().upper;
    double fly = ui->timeWave->yAxis->range().lower, fhy = ui->timeWave->yAxis->range().upper;
    double tkey = ui->timeWave->xAxis->pixelToCoord(x);
    double fkey = ui->freqWave->xAxis->pixelToCoord(x);

    double y = e->pos().y();
    double tlx = ui->timeWave->xAxis->range().lower, thx = ui->timeWave->xAxis->range().upper;
    double flx = ui->timeWave->xAxis->range().lower, fhx = ui->timeWave->xAxis->range().upper;
    double txkey = ui->timeWave->yAxis->pixelToCoord(y);
    double fxkey = ui->freqWave->yAxis->pixelToCoord(y);
//    bool timewave = true;
    if(ui->timeWave->geometry().contains(this->mapFromGlobal(QCursor::pos())))
    {
//        timewave = true;
        m_vTimeTrackLine->setVisible(true);
        m_vTimeTrackLine->point1->setCoords(tkey, tly);
        m_vTimeTrackLine->point2->setCoords(tkey, thy);

        m_hTimeTrackLine->setVisible(true);
        m_hTimeTrackLine->point1->setCoords(tlx, txkey);
        m_hTimeTrackLine->point2->setCoords(thx, txkey);
        for(int i = 0; i < m_timeTracerList.size(); i++)
        {
            m_timeTracerList.at(i)->setVisible(true);
            m_timeTracerList.at(i)->setGraph(ui->timeWave->graph(i));
            m_timeTracerList.at(i)->setGraphKey(tkey);
        }
        QString str = QString("x:%1, y:%2").arg(tkey).arg(txkey);
        m_timeText->setText(str);

        m_vFreqTrackLine->setVisible(false);
        m_hFreqTrackLine->setVisible(false);
        for(auto d : m_freqTracerList)
        {
            d->setVisible(false);
        }
        ui->timeWave->replot();
        ui->freqWave->replot();
    }
    else if(ui->freqWave->geometry().contains(this->mapFromGlobal(QCursor::pos())))
    {
        m_vTimeTrackLine->setVisible(false);
        m_hTimeTrackLine->setVisible(false);
        for(auto d : m_timeTracerList)
        {
            d->setVisible(false);
        }
        QString str = QString(" x:%1, y:%2").arg(fkey).arg(fxkey);
        m_freqText->setText(str);

        m_vFreqTrackLine->setVisible(true);
        m_vFreqTrackLine->point1->setCoords(fkey, fly);
        m_vFreqTrackLine->point2->setCoords(fkey, fhy);

        m_hFreqTrackLine->setVisible(true);
        m_hFreqTrackLine->point1->setCoords(flx, fxkey);
        m_hFreqTrackLine->point2->setCoords(fhx, fxkey);
        for(int i = 0; i < m_freqTracerList.size(); i++)
        {
            m_freqTracerList.at(i)->setVisible(true);
            m_freqTracerList.at(i)->setGraph(ui->freqWave->graph(i));
            m_freqTracerList.at(i)->setGraphKey(fkey);
        }
        ui->timeWave->replot();
        ui->freqWave->replot();
    }
    else
    {
        m_vTimeTrackLine->setVisible(false);
        m_hTimeTrackLine->setVisible(false);
        m_timeText->setVisible(false);
        for(auto d : m_timeTracerList)
        {
            d->setVisible(false);
        }

        m_vFreqTrackLine->setVisible(false);
        m_hFreqTrackLine->setVisible(false);
        m_freqText->setVisible(false);
        for(auto d : m_freqTracerList)
        {
            d->setVisible(false);
        }
        ui->timeWave->replot();
        ui->freqWave->replot();
        return;
    }

    QWidget::mouseMoveEvent(e);
}

void ChartWave::mouseReleaseEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
    {
    }
    QWidget::mouseReleaseEvent(e);
}
